<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI助手</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
        body { background-color: #f5f5f7; color: #333; min-height: 100vh; }
        .container { display: flex; flex-direction: column; height: 100vh; max-width: 800px; margin: 0 auto; }
        .header { padding: 16px; text-align: center; border-bottom: 1px solid #e0e0e0; background-color: white; }
        .header h1 { font-size: 20px; font-weight: 600; color: #1a1a1a; }
        .chat-container { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 20px; scroll-behavior: smooth; }
        .chat-message { display: flex; gap: 12px; max-width: 85%; }
        .chat-message.user { align-self: flex-end; flex-direction: row-reverse; }
        .avatar { width: 40px; height: 40px; border-radius: 50%; background-color: #e0e0e0; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
        .avatar.ai { background-color: #007bff; color: white; }
        .avatar.user { background-color: #4caf50; color: white; }
        .message-bubble { padding: 12px 16px; border-radius: 18px; line-height: 1.5; word-wrap: break-word; } /* 添加 word-wrap 防止长文本溢出 */
        .message-bubble.ai { background-color: white; border: 1px solid #e0e0e0; border-top-left-radius: 4px; box-shadow: 0 1px 2px rgba(0,0,0,0.05); }
        .message-bubble.user { background-color: #007bff; color: white; border-top-right-radius: 4px; }
        .typing-indicator { display: flex; gap: 4px; padding: 10px; }
        .typing-indicator span { width: 8px; height: 8px; background-color: #999; border-radius: 50%; animation: typing 1.4s infinite ease-in-out both; }
        .typing-indicator span:nth-child(1) { animation-delay: -0.32s; }
        .typing-indicator span:nth-child(2) { animation-delay: -0.16s; }
        @keyframes typing { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } }
        .input-container { padding: 16px; background-color: white; border-top: 1px solid #e0e0e0; }
        .input-wrapper { position: relative; }
        #userInput { width: 100%; padding: 14px 50px 14px 16px; border: 1px solid #e0e0e0; border-radius: 24px; font-size: 16px; resize: none; height: 52px; line-height: 24px; }
        #userInput:focus { outline: none; border-color: #007bff; box-shadow: 0 0 0 2px rgba(0,123,255,0.1); }
        #sendBtn { position: absolute; right: 12px; bottom: 12px; width: 36px; height: 36px; border-radius: 50%; background-color: #007bff; color: white; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background-color 0.2s; }
        #sendBtn:hover { background-color: #0056b3; }
        #sendBtn:disabled { background-color: #6c757d; cursor: not-allowed; }
        .system-prompt { background-color: #f0f7ff; padding: 12px 16px; border-radius: 12px; font-size: 14px; color: #4a4a4a; margin-bottom: 10px; }
        /* 工具调用提示弹窗样式（确保高优先级显示） */
        .tool-notify-popup {
            position: fixed;
            top: 20px;
            right: 20px;
            background-color: #2c3e50;
            color: white;
            padding: 12px 20px;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            font-size: 14px;
            z-index: 9999; /* 提高层级确保可见 */
            opacity: 0;
            transform: translateY(-20px);
            transition: all 0.3s ease-out;
            pointer-events: none; /* 不影响底层交互 */
        }
        /* 弹窗显示状态 */
        .tool-notify-popup.show {
            opacity: 1;
            transform: translateY(0);
        }
    </style>
</head>
<body>
<div class="container">
    <div class="header">
        <h1>AI助手</h1>
    </div>
    <div class="chat-container" id="chatContainer">
        <div class="system-prompt">
            我是AI助手，可以回答您的问题。请输入您想了解的内容...
        </div>
    </div>
    <div class="input-container">
        <div class="input-wrapper">
            <textarea id="userInput" placeholder="输入您的问题..."></textarea>
            <button id="sendBtn">➤</button>
        </div>
    </div>
</div>
<!-- 工具调用提示弹窗（确保DOM存在） -->
<div class="tool-notify-popup" id="toolNotifyPopup"></div>
<script>
    // 确保DOM加载完成后获取元素
    document.addEventListener('DOMContentLoaded', function() {
        const userInput = document.getElementById('userInput');
        const sendBtn = document.getElementById('sendBtn');
        const chatContainer = document.getElementById('chatContainer');
        const toolNotifyPopup = document.getElementById('toolNotifyPopup');

        let eventSource = null; // 用于存储 EventSource 实例

        // 初始化SSE连接，监听工具调用通知
        function initSseConnection() {
            // 处理本地开发跨域问题（根据实际后端地址调整）
            const baseUrl = window.location.origin;
            const sseUrl = `http://localhost:8081/sse/subscribe`;
            console.log("尝试连接SSE:", sseUrl);

            // 关闭之前的连接（如果有的话）
            if (eventSource) {
                eventSource.close();
                console.log("已关闭之前的SSE连接");
            }

            eventSource = new EventSource(sseUrl);

            eventSource.onopen = function() {
                console.log("SSE连接已建立，等待工具调用通知...");
            };

            // 接收工具调用通知
            eventSource.addEventListener("toolInvoke", function(event) {
                console.log("收到工具调用通知:", event.data);
                showToolNotify(event.data);
            });

            // 错误处理
            eventSource.onerror = function(error) {
                console.error("SSE连接错误:", error);
                // 检查连接是否已经关闭，避免无限重试
                if (eventSource.readyState === EventSource.CONNECTING) {
                    // 3秒后重试连接
                    console.log("SSE连接断开，将在3秒后尝试重连...");
                    setTimeout(initSseConnection, 3000);
                } else if (eventSource.readyState === EventSource.CLOSED) {
                    console.log("SSE连接已关闭，停止重连。");
                }
            };
        }

        // 显示工具调用提示弹窗，仅展示工具名称，3秒后自动消失
        function showToolNotify(message) {
            if (!toolNotifyPopup) {
                console.error("弹窗元素未找到！");
                return;
            }
            // 提取工具名称（兼容不同格式的消息）
            let toolName = "未知工具";
            // 尝试从消息中提取工具名（适配后端可能的不同格式）
            if (message.includes("工具【")) {
                const match = message.match(/工具【(.*?)】/);
                if (match && match[1]) toolName = match[1];
            } else if (message.includes("调用了")) {
                const match = message.match(/调用了(.*?)，/);
                if (match && match[1]) toolName = match[1];
            }
            // 设置弹窗内容
            toolNotifyPopup.textContent = `正在调用${toolName}工具`;
            // 强制显示弹窗
            toolNotifyPopup.classList.add('show');
            // 手动触发重绘
            void toolNotifyPopup.offsetWidth;
            // 3秒后隐藏
            setTimeout(() => {
                toolNotifyPopup.classList.remove('show');
            }, 3000);
        }

        // 自动调整输入框高度
        userInput.addEventListener('input', () => {
            userInput.style.height = 'auto';
            const newHeight = Math.min(userInput.scrollHeight, 120); // 限制最大高度
            userInput.style.height = `${newHeight}px`;
        });

        // 发送消息事件监听
        sendBtn.addEventListener('click', sendMessage);
        userInput.addEventListener('keydown', (e) => {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                sendMessage();
            }
        });

        async function sendMessage() {
            const message = userInput.value.trim();
            if (!message) return;
            // 添加用户消息到对话
            addMessageToChat(message, 'user');
            userInput.value = '';
            userInput.style.height = '52px'; // 重置高度
            sendBtn.disabled = true;
            // 添加AI正在输入的指示器
            const typingIndicator = addTypingIndicator();
            try {
                // 发送请求到后端API（根据实际地址调整）
                const response = await fetch(`http://localhost:8081/ai?userInput=${encodeURIComponent(message)}`);
                if (!response.ok) {
                    throw new Error(`请求失败: ${response.status}`);
                }
                // 移除输入指示器
                if (typingIndicator.parentNode === chatContainer) {
                    chatContainer.removeChild(typingIndicator);
                }
                // 添加AI响应消息容器
                const aiMessageElement = addMessageToChat('', 'ai', true);
                const messageBubble = aiMessageElement.querySelector('.message-bubble');

                // 处理流式响应
                const reader = response.body.getReader();
                const decoder = new TextDecoder('utf-8');
                try {
                    while (true) {
                        const { done, value } = await reader.read();
                        if (done) break;
                        const text = decoder.decode(value, { stream: true });
                        messageBubble.textContent += text;
                        // 滚动到底部
                        chatContainer.scrollTop = chatContainer.scrollHeight;
                    }
                } finally {
                    // 确保流被关闭
                    reader.releaseLock();
                }
            } catch (error) {
                // 移除输入指示器并显示错误
                if (typingIndicator.parentNode === chatContainer) {
                    chatContainer.removeChild(typingIndicator);
                }
                if (error.name === 'TypeError') {
                    addMessageToChat(`网络错误: 无法连接到服务器，请检查后端是否已启动`, 'ai');
                } else {
                    addMessageToChat(`发生错误: ${error.message}`, 'ai');
                }
                console.error('详细错误信息:', error);
            } finally {
                sendBtn.disabled = false;
            }
        }

        function addMessageToChat(text, sender, isStreaming = false) {
            const messageDiv = document.createElement('div');
            messageDiv.className = `chat-message ${sender}`;
            const avatarDiv = document.createElement('div');
            avatarDiv.className = `avatar ${sender}`;
            avatarDiv.textContent = sender === 'user' ? '你' : 'AI';
            const bubbleDiv = document.createElement('div');
            bubbleDiv.className = `message-bubble ${sender}`;
            bubbleDiv.textContent = text;
            messageDiv.appendChild(avatarDiv);
            messageDiv.appendChild(bubbleDiv);
            chatContainer.appendChild(messageDiv);
            chatContainer.scrollTop = chatContainer.scrollHeight;
            return isStreaming ? messageDiv : null;
        }

        function addTypingIndicator() {
            const typingDiv = document.createElement('div');
            typingDiv.className = 'chat-message ai';
            const avatarDiv = document.createElement('div');
            avatarDiv.className = 'avatar ai';
            avatarDiv.textContent = 'AI';
            const indicatorDiv = document.createElement('div');
            indicatorDiv.className = 'typing-indicator message-bubble ai';
            indicatorDiv.innerHTML = '<span></span><span></span><span></span>';
            typingDiv.appendChild(avatarDiv);
            typingDiv.appendChild(indicatorDiv);
            chatContainer.appendChild(typingDiv);
            chatContainer.scrollTop = chatContainer.scrollHeight;
            return typingDiv;
        }

        // --- 内存泄漏防护：页面卸载时清理资源 ---
        window.addEventListener('beforeunload', function() {
            console.log("页面即将卸载，正在清理资源...");
            // 关闭SSE连接
            if (eventSource) {
                eventSource.close();
                console.log("SSE连接已关闭。");
            }
            // 移除所有可能的定时器（虽然当前代码中只有一个，但这是个好习惯）
            // 注意：这里没有创建全局定时器，但如果有的话需要清理
            // 例如：if (someTimerId) clearTimeout(someTimerId);

            // 移除事件监听器（对于通过addEventListener添加的监听器，现代浏览器在页面卸载时通常会自动清理，
            // 但显式移除是更安全的做法，尤其是在SPA中）
            // 由于这些监听器是匿名函数，直接移除比较困难。
            // 一个更好的做法是使用具名函数，然后在这里removeEventListener。
            // 但对于这个简单的页面，且即将卸载，影响不大。
            // 如果需要更严格的控制，可以重构事件监听器为具名函数。
        });

        // 初始化SSE连接
        initSseConnection();

    });
</script>
</body>
</html>